package com.lmz.project.redis.arithmetic.heapShed;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class QueueAndCircular {
    /**
     * 队列 排队 从尾进入，从头出，先进先出
     * 栈： 弹夹 先进，压入到最下面，一层一层压
     */
    public static class Queue1 {
        //Java中的双向链表LinkedList
        //单项链表就足够了
        public Queue<Integer> queue = new LinkedList<>();

        //调用任何方法之前，先调用这个方法来判断队列内是否有东西
        public boolean isEmpty() {
            return queue.isEmpty();
        }

        //想队列中加入num，加到尾
        public void offer(int num) {
            queue.offer(num);
        }

        //从队列拿，从头拿
        public int poll() {
            return queue.poll();
        }

        //返回队列的头元素，但是不弹出
        public int peek() {
            return queue.peek();
        }

        //返回目前队列的元素个数
        public int size() {
            return queue.size();
        }
    }

    //实际刷题时更常见用数组去构造队列
    //一般笔试、面试都会有一个明确的数量，所以这是最常用的方式
    public static class Queue2 {
        public int[] queue;
        public int l;
        public int r;

        //加入操作的总次数上限是多少，一定要明确
        public Queue2(int n) {
            queue = new int[n];
            l = 0;
            r = 0;
        }

        //调用任何方法之前，先调用这个方法来判断队列内是否有东西
        //r>l 代表有数据，l=r 代表无数据
        public boolean isEmpty() {
            return l == r;
        }

        public void offer(int num) {
            queue[r] = num;
            r++;
        }

        //弹出一个数 头弹出
        public int poll() {
            int result = queue[l];
            l++;
            return result;
        }

        public int head() {
            return queue[l];
        }

        public int tail() {
            return queue[r - 1];
        }

        public int size() {
            return r - l;
        }

    }


    //直接用java内部的实现
    //其实就是动态数组，不过常数时间并不好
    public static class Stack1 {
        public Stack<Integer> stack = new Stack<>();

        //调用任何方法之前，先调用这个方法来判断栈内是否有东西
        public boolean isEmpty() {
            return stack.isEmpty();
        }

        public void push(int num) {
            stack.push(num);
        }

        public int pop() {
            return stack.pop();
        }

        //返回栈顶元素，不弹出
        public int peek() {
            return stack.peek();
        }

        public int size() {
            return stack.size();
        }

    }

    /**
     * 实际刷题时更常见的写法
     * 如果考虑保证同时在栈里的元素个数不会超过n，那么可以用
     * 也就是发生弹出的操作后，空间可以复用
     * 一般笔试、面试都会有以哦个明确的数据量，所以这是最常用的方式
     */
    public static class Stack2 {
        public int[] stack;
        public int size;

        //同时在栈里的元素个数不会超过n
        public Stack2(int n) {
            stack = new int[n];
            size = 0;
        }

        //调用任何方法之前，先调用这个方法来判断栈内是否有东西
        public boolean isEmpty() {
            return size == 0;
        }

        public void push(int num) {
            stack[size++] = num;
        }

        public int pop() {
            return stack[--size]; //弹出 size-1的位置的元素，并且size--
        }

        //返回栈顶元素，不弹出
        public int peek() {
            return stack[size - 1];
        }

        public int size() {
            return size;
        }
    }


    //环形队列
    //头 =0 尾=0 size=0  limit 数组长度
    //加入 x,放到尾，尾++， 结束尾回到0 size++  前提 size < limit
    //弹出头，拿头，头++ 结束 头回到0 size-- 前提 size >0

    /**
     * 设计循环队列
     * 测试链接：https://leetcode.cn/problems/design-circular-queue/description/
     */

    class MyCircularQueue {

        public int[] queue;

        public int l, r, size, limit;

        public MyCircularQueue(int k) {
            queue = new int[k];
            l = r = size = 0;
            limit = k;
        }

        //添加一个元素
        //如果队列满了，什么也不做，返回false
        //如果队列没满，加入value，返回true
        public boolean enQueue(int value) {
            if (isFull()) {
                return false;
            } else {
                queue[r] = value;
                // r++ 结束了，跳回0
                r = r == limit - 1 ? 0 : r + 1;
                size++;
                return true;
            }
        }

        //弹出一个元素
        //如果队列空了，什么也不做，返回false
        //如果队列没空，弹出value，返回true
        public boolean deQueue() {
            if (isEmpty()) {
                return false;
            } else {
                l = l == limit - 1 ? 0 : l + 1;
                size--;
                return true;
            }
        }

        //返回队列头部的数字(不弹出)，如果没有数返回-1
        public int Front() {
            if (isEmpty()) {
                return -1;
            } else {
                return queue[l];
            }
        }

        //返回队列尾部的数字，如果没有返回-1;
        public int Rear() {
            if (isEmpty()) {
                return -1;
            } else {
                int last = r == 0 ? limit - 1 : r - 1;
                return queue[last];
            }
        }


        public boolean isEmpty() {
            return size == 0;
        }

        public boolean isFull() {
            return size == limit;
        }
    }






}
